package com.jdd.fintech.morse.plugin;

import com.alibaba.fastjson.JSONObject;
import com.jd.fastjson.JSON;
import com.jdd.fintech.morse.plugin.constans.OpenApiConstans;
import com.jdd.fintech.morse.plugin.ecrypts.SymmetricCrypto;
import com.jdd.fintech.morse.plugin.enums.*;
import com.jdd.fintech.morse.plugin.plugconfig.MorsePlugValueConfig;
import com.jdd.fintech.morse.plugin.strategy.context.DataEncryptAndDecryptStrategyContext;
import com.jdd.fintech.morse.plugin.util.CryptoUtils;
import com.jdd.fintech.morse.plugin.util.PluginDateUtils;
import com.jddglobal.filter.Filter;
import com.jddglobal.filter.data.Context;
import com.jddglobal.filter.data.ContextHttpKey;
import com.jddglobal.filter.data.Resource;
import com.jddglobal.filter.support.exception.FilterException;
import com.jddglobal.phevos.gateway.resources.ResourceCapability;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.List;

import static com.jdd.fintech.morse.plugin.constans.OpenApiConstans.*;
import static com.jdd.fintech.morse.plugin.util.CommonMethodUtils.getCustomerVersion;
import static com.jdd.fintech.morse.plugin.util.CommonMethodUtils.isItSymmetricalEncryptionAndDecryption;
import static com.jdd.fintech.morse.plugin.util.CryptoUtils.checkSecurityLength;

/**
 * @Description Morse 加密插件
 * @Author fengcheng
 * @Date 2021/02/05
 * @Version 1.0
 * @date 2022-11-18 09:47
 * @author ext.fengcheng
 */
public class MorseOpenApiEncryptsFilter implements Filter {

    /**
     * 日志输出对象
     */
    private static final Logger log = LoggerFactory.getLogger(MorseOpenApiEncryptsFilter.class);

    @Override
    public <R, S> Resource<Object> filter(Context<R, S> context, List<ConfigurationValue> dynamic) throws FilterException {
        try {
            log.info("MorseOpenApiEncryptsFilter.filter.开始执行Morse-OpenApi-加密插件");
            //1.获取插件值中的配置
            if (CollectionUtils.isEmpty(dynamic)) {
                throw new FilterException(new ResourceCapability.AutoDefineResource(BizErrorCodeEnum.FAILURE_2.getCode(), BizErrorCodeEnum.FAILURE_2.getDesc()));
            }
            JSONObject jsonObject = null;
            RequestDateDirectionEnum directionEnum = null;
            for (ConfigurationValue obj : dynamic) {
                String settingValue = obj.getSettingValue();
                if (StringUtils.isBlank(settingValue)) {
                    continue;
                }
                JSONObject json = JSONObject.parseObject(settingValue);
                //获取插件值配置对象
                MorsePlugValueConfig plugValueConfig = JSON.parseObject(json.toJSONString(), MorsePlugValueConfig.class);
                //获取参数入口方向
                String data;
                directionEnum = plugValueConfig.getRequestDateDirection();
                if(RequestDateDirectionEnum.REQUEST.getCode().equals(directionEnum.getCode())){
                    jsonObject = JSON.parseObject(context.getRequest().getBody().toString(), JSONObject.class);
                    if (ObjectUtils.isEmpty(jsonObject)) {
                        log.error(OpenApiConstans.DATA_IS_NULL);
                        return Resource.OK();
                    }
                } else{
                    //获取需要加密的明文字符串
                    Resource<Object> responseBody = context.getResponse().getBody();
                    if (ObjectUtils.isEmpty(responseBody)) {
                        log.error(OpenApiConstans.RESPONST_IS_NULL);
                        return Resource.OK();
                    }
                    JSONObject responseBodyJsonObject = JSON.parseObject(JSON.toJSONString(responseBody), JSONObject.class);
                    jsonObject = responseBodyJsonObject.getJSONObject("data");
                    if(ObjectUtils.isEmpty(jsonObject)){
                        log.error(RESPONST_IS_NULL);
                        return Resource.OK();
                    }
                }
                log.debug("MorseOpenApiEncryptsFilter.filter.Morse-OpenApi-加密插件|加密插件-加密请求参数:{}", jsonObject.toJSONString());
                //是否是对称加解密，对称加密返回：true；非对称加解密返回：false
                boolean flag = isItSymmetricalEncryptionAndDecryption(plugValueConfig);
                if(flag){
                    //对称加解密，走此加解密逻辑，并开始构建加密对象
                    bulidAndEexecutEncrypts(plugValueConfig, jsonObject);
                } else {
                    //非对称加解密，走此加解密逻辑，并且不需要初始化加解密算法对象，默认为: null即可
                    encryptByVersion(plugValueConfig, jsonObject, null);
                    if(plugValueConfig.getCustomVersion().equals(CustomVersionEnum.YGC)){
                        JSONObject extendParameter = JSONObject.parseObject(plugValueConfig.getExtendParameter());
                        context.getRequest().setHeader(ContextHttpKey.RequestHeader.MORSE_YGC_SECRET_KEY, extendParameter.getString(YGC_SECRET_KEY));
                        context.getRequest().setHeader(ContextHttpKey.RequestHeader.MORSE_YGC_ENCRYPT_ALG, extendParameter.getString(YGC_ENCRYPT_ALG));
                        context.getRequest().setHeader(ContextHttpKey.RequestHeader.MORSE_YGC_SIGN_ALG, extendParameter.getString(YGC_SIGN_ALG));
                        context.getRequest().setHeader(ContextHttpKey.RequestHeader.MORSE_YGC_SIGN, jsonObject.getString(YGC_DATA_SIGN_KEY));
                        context.getRequest().setHeader(ContextHttpKey.RequestHeader.MORSE_YGC_TIMESTAMP, PluginDateUtils.getYYYYMMddHHmmsssss());
                        context.getRequest().setHeader(ContextHttpKey.RequestHeader.MORSE_YGC_VERSION, HEADER_VERSION_VALUE);
                        jsonObject.remove(YGC_DATA_SIGN_KEY);
                    }
                }
            }
            if(ObjectUtils.isEmpty(jsonObject)){
                return Resource.OK();
            }
            String body = jsonObject.toJSONString();
            log.debug("MorseOpenApiEncryptsFilter.filter.Morse-OpenApi-加密插件|执行完成, 加密成功后的数据：{}", body);
            if(RequestDateDirectionEnum.REQUEST.getCode().equals(directionEnum.getCode())){
                context.getRequest().setBody(body);
            } else{
                context.getResponse().setBody(Resource.<Object>OK(body));
            }
        } catch (Exception e) {
            log.error("Morse请求对象加密失败|异常信息:{}", e.getMessage(), e);
            throw new FilterException(new ResourceCapability.AutoDefineResource(BizErrorCodeEnum.FAILURE_3.getCode(), BizErrorCodeEnum.FAILURE_3.getDesc()));
        }
        return Resource.OK();
    }

    /**
     * 开始构建加密对象并执行加密逻辑
     * @param plugValueConfig
     * @param jsonObject
     * @throws FilterException
     */
    public void bulidAndEexecutEncrypts(MorsePlugValueConfig plugValueConfig, JSONObject jsonObject) throws FilterException {
        if (BooleanEnum.YES.getCode().equals(plugValueConfig.getEncyAndDecyFlag().getCode())) {
            log.info("MorseOpenApiEncryptsFilter.bulidAndEexecutEncrypts.开始构建加密对象并执行加密逻辑");
            //获取插件值对象中的密钥
            String publicSecurity = plugValueConfig.getPublicSecurity();
            //检查加密相对应的密钥长度是否超长(只针对对称式加解密)
            checkSecurityLength(publicSecurity, plugValueConfig);
            //加解密类型
            EncrAndDecrAlgorithmTypeEnum encyAndDecyType = plugValueConfig.getEncyAndDecyType();
            //解密模式
            String encryptMode = plugValueConfig.getEncryptMode().getValue();
            //密钥长度
            int secretKeyLength = plugValueConfig.getKeySize();
            //根据解密类型生成对称解密算法对象
            SymmetricCrypto scObj = CryptoUtils.generateSymmetricCrypto(encyAndDecyType, publicSecurity, encryptMode, secretKeyLength);
            //开始进行参数加密操作
            encryptByVersion(plugValueConfig, jsonObject, scObj);
        } else {
            log.info("MorseOpenApiEncryptsFilter.bulidAndEexecutEncrypts.不需要进行加密，是否配置加解密配置值.encyAndDecyFlag: {}", plugValueConfig.getEncyAndDecyFlag().getCode());
        }
    }

    /**
     * 定制化加密
     * @param plugValueConfig
     * @param jsonObject
     * @param scObj
     * @return
     * @throws FilterException
     */
    public String encryptByVersion(MorsePlugValueConfig plugValueConfig, JSONObject jsonObject, SymmetricCrypto scObj) throws FilterException {
        log.info("MorseOpenApiEncryptsFilter.encryptByVersion.开始定制化加密逻辑");
        CustomVersionEnum customVersion = plugValueConfig.getCustomVersion();
        customVersion = getCustomerVersion(customVersion);
        //根据定制化版本获取对应的策略类
        DataEncryptAndDecryptStrategyContext context = new DataEncryptAndDecryptStrategyContext(customVersion);
        //调用数据加密策略方法
        return context.dataEncryptsStrategyMethod(plugValueConfig, jsonObject, scObj);
    }
}
